Strict
Import mojo
Import agfx


Class TSprite Extends TEntity

	Field bitmap:TImage
	
	Field offset:TVector2
	Field scale:TVector2
	
	' color
	
	Field alpha:Float 			= 1.0
	Field red:Int 				= 255
	Field green:Int 			= 255
	Field blue:Int 				= 255
	
	
	Private
	
	Field debug:Bool = False
	

	' Animation
	Field frame:Int
	Field frameTimer:Int
	Field frameStart:Int
	Field frameEnd:Int
	Field frameSpeed:Int = 0 
	Field reverse:Bool = False
	Field pingPong:Bool = False
	Field loop:Bool = True
	Field ping%
	
	
	' Scale
	Field scaleCounter:Float	= 0
	Field scaleTmpCounter:Float	= 0
	Field scaleSpeed:TVector2 	= New TVector2(0.1,0.1)
	Field maxFrame:Int			= 0
	Field scaleLoop:Bool		= False
	Field scalePingpong:Bool	= False
	Field scaleDir:Int			= 1
	Field scaleTmp:TVector2		= New TVector2(1,1)
	Field flip:TVector2			= New TVector2(1,1)
	Field event_scale_done:Bool = False
	Field event_scale_loop:Int  = 0
	
	' Alpha
	Field alphaCounter:Float	= 0
	Field alphaTmpCounter:Float	= 0
	Field alphaSpeed:Float 		= 0.1
	Field alphaLoop:Bool		= False
	Field alphaPingpong:Bool	= False
	Field alphaDir:FLoat		= 1.0
	Field alphaTmp:Float		= 1.0
	Field event_alpha_done:Bool = False
	Field event_alpha_loop:Int  = 0

	' Rotation
	Field rotationCounter:Float	= 0
	Field rotationLength:Int	= 1000
	Field rotationLoop:Int 		= 0
	Field rotationSpeed:Float 	= 1
	Field rotationTmp:Float		= 0
	Field rotationCounterTmp:Float	= 0
	Field rotationpingpong:Bool	= False
	Field rotationDir:Float	    = 1.0
	Field event_rotation_done:Bool = False
	Field event_rotation_loop:Int  = 0

	Public
	
	'|--------------------------------------------------------------------------------
	'| Constructor
	'|--------------------------------------------------------------------------------
	Method New(n:String,img:TImage,x:Float=0, y:Float=0)
	
		Self.bitmap = img
		Self.name = n
		Self.speed = 1.0
		Self.scale = New TVector2(1,1)
		Self.position.Set(x,y)	
		Self.size.Set(Self.bitmap.image.Width(),Self.bitmap.image.Height())	
		Self.visible = True
		Self.rotation = 0
		Self.radius = Self.size.x/2
		Self.offset = New TVector2(0,0)
		Self.collision.Set(Self.position,Self.size,Self.radius)
	End
	
	'|--------------------------------------------------------------------------------
	'| SetSize
	'|--------------------------------------------------------------------------------
	Method SetSize:Void(sx:Int,sy:Int)
		Self.size.Set(sx,sy)
		Self.collision.Set(Self.position,Self.size,sx/2.0)
		Self.scale.Set(sx/Self.bitmap.image.Width(),sy/Self.bitmap.image.Height())
	End Method
	
	'|--------------------------------------------------------------------------------
	'| SetScale
	'|--------------------------------------------------------------------------------
	Method SetScale:Void(sx:Float,sy:Float)
		Self.scale.Set(sx,sy)
		Self.size.Set(Self.bitmap.image.Width()*sx,Self.bitmap.image.Height()*sy)
		Self.collision.Set(Self.position,Self.size,Self.size.x/2.0)
	End Method

	'|--------------------------------------------------------------------------------
	'| SetScale
	'|--------------------------------------------------------------------------------
	Method SetScale:Void(s:TVector2)
		Self.SetScale(s.x,s.y)
	End Method

	'|--------------------------------------------------------------------------------
	'| Set alpha
	'|--------------------------------------------------------------------------------
	Method SetTransparency:Void(a:Float)
		Self.alpha = a
	End Method
	
	
	'|--------------------------------------------------------------------------------
	'| Get alpha
	'|--------------------------------------------------------------------------------
	Method GetTransparency:Float()
		Return Self.alpha
	End Method

	'|--------------------------------------------------------------------------------
	'| Set RGB color
	'|--------------------------------------------------------------------------------
	Method SetRGB:Void(r:Int,g:Int,b:Int)
		Self.red = r
		Self.green = g
		Self.blue = b
		
	End Method
	
	'|--------------------------------------------------------------------------------
	'| Set RGB color
	'|--------------------------------------------------------------------------------
	Method SetRGBA:Void(r:Int,g:Int,b:Int,a:Int)
		Self.red = r
		Self.green = g
		Self.blue = b
		Self.alpha = a/255.0		
	End Method
	
	'|--------------------------------------------------------------------------------
	'| Flip sprite image
	'|--------------------------------------------------------------------------------
	Method SetFlip:Void(fx:Bool,fy:Bool)
		If (fx) Then Self.flip.x = -1 Else Self.flip.x = 1
		If (fy) Then Self.flip.y = -1 Else Self.flip.y = 1
	End Method
	
	'|--------------------------------------------------------------------------------
	'| set/change sprite image
	'|--------------------------------------------------------------------------------
	Method SetImage:Void(gi:TImage)
		Self.bitmap = gi
		If Self.bitmap <> Null Then Self.bitmap.CalcSize()
	End

	'|--------------------------------------------------------------------------------
	'| debug true/false
	'|--------------------------------------------------------------------------------
	Method SetDebug:Void(state:Bool)
		Self.debug = state
	End Method

	'|--------------------------------------------------------------------------------
	'| Set Scale event
	'|--------------------------------------------------------------------------------
	Method SetScaleEvent:Void(sc:Int,speed_sx:Float,speed_sy:Float,loop:Bool=False,pingpong:Bool=False)
	
		Self.scaleSpeed.Set(speed_sx,speed_sy)
		Self.scaleTmp.Set(Self.scale.x,Self.scale.y)
		Self.scaleCounter 	 = sc		
		Self.scaleTmpCounter = sc		
		Self.scaleLoop 		 = loop
		Self.scalePingpong 	 = pingpong
		Self.scaleDir 		 = 1
		Self.event_scale_done = False
		Self.event_scale_loop = 0
		
	End Method
	

	'|--------------------------------------------------------------------------------
	'| Manage control of scale (onUpdate)
	'|--------------------------------------------------------------------------------
	Method ManageScaleEvent:Void()
	
		If Self.scaleCounter>0 Then
			Self.scaleCounter-=1*AppSpeed()
			Self.scale.x += Self.scaleSpeed.x*AppSpeed()*Self.scaleDir
			Self.scale.y += Self.scaleSpeed.y*AppSpeed()*Self.scaleDir
		Else
				
			Self.event_scale_done = True

			If Self.scaleLoop Then
				Self.event_scale_loop += 1
				Self.scaleCounter = Self.scaleTmpCounter
				If Self.scalePingpong=False Then
					Self.scale.Set(Self.scaleTmp.x,Self.scaleTmp.y)
				End
				Self.event_scale_done = False
			EndIf
			
			If Self.scalePingpong Then
				Self.scaleDir = -Self.scaleDir
				Self.event_scale_done = False
			EndIf

			
		End
	End
	
	'|--------------------------------------------------------------------------------
	'| Set Alpha event
	'|--------------------------------------------------------------------------------
	Method SetAlphaEvent:Void(sc:Int,speed_a:Float,start_alpha:Float,loop:Bool=False,pingpong:Bool=False)
	
		Self.alphaSpeed		 = speed_a
		Self.alpha 			 = start_alpha
		Self.alphaTmp 		 = Self.alpha
		Self.alphaCounter 	 = sc		
		Self.alphaTmpCounter = sc		
		Self.alphaLoop 		 = loop
		Self.alphaPingpong 	 = pingpong
		Self.alphaDir 		 = 1.0
		Self.event_alpha_done = False
		Self.event_alpha_loop = 0
	End Method


	'|--------------------------------------------------------------------------------
	'| Manage control of alpha (onUpdate)
	'|--------------------------------------------------------------------------------
	Method ManageAlphaEvent:Void()
	
		
		If Self.alphaCounter>0 Then
			Self.alphaCounter-=1.0*AppSpeed()
			Self.alpha += Self.alphaSpeed *AppSpeed()*Self.alphaDir
			
		Else
			Self.event_alpha_done = True

			If Self.alphaLoop Then
				Self.event_alpha_loop += 1
				Self.alphaCounter = Self.alphaTmpCounter
				If Self.alphaPingpong=False Then
					Self.alpha = Self.alphaTmp
				End
				Self.event_alpha_done = False
			EndIf
			
			If Self.alphaPingpong Then
				Self.event_alpha_done = False
				Self.alphaDir = -Self.alphaDir
			EndIf

		End
	End

	'|--------------------------------------------------------------------------------
	'| Set rotation Event
	'|--------------------------------------------------------------------------------
	Method SetRotationEvent:Void(length:Int, rotationSpeed:Float, loop:Bool = False, pingpong:Bool = False, rndPosition:Bool = False)	
		
		If rndPosition Then rotation = Rnd(0,360)
		
		Self.rotationSpeed 		= rotationSpeed ' delta angle
		Self.rotationTmp 		= Self.rotation
		Self.rotationCounter 	= length	
		Self.rotationCounterTmp = length		
		Self.rotationLoop 		= loop
		Self.rotationpingpong 	= pingpong
		Self.rotationDir 		 = 1.0
		Self.event_rotation_done = False
		Self.event_rotation_loop = 0
	End
	
	'|--------------------------------------------------------------------------------
	'| Manage control of scale (onUpdate)
	'|--------------------------------------------------------------------------------
	Method ManageRotationEvent:Void()
	
		If Self.rotationCounter>0 Then
			Self.rotationCounter-=1 * AppSpeed()
			Self.rotation+=Self.rotationSpeed * AppSpeed() * Self.rotationDir
		Else			
			Self.event_rotation_done = True
			If Self.rotationLoop Then	
				Self.event_rotation_loop += 1	
				Self.rotationCounter = Self.rotationCounterTmp				
				Self.event_rotation_done = False
			EndIf	
			
			If Self.rotationpingpong Then
				Self.rotationDir =  -Self.rotationDir
				Self.event_rotation_done = False
			EndIf
			
		End
		
	End

	'|--------------------------------------------------------------------------------
	'| Set animation frame
	'|--------------------------------------------------------------------------------	
	Method SetFrame:Void(f:Int)
		Self.frame = f
	End Method
	
	'|--------------------------------------------------------------------------------
	'| Set animation frame
	'|--------------------------------------------------------------------------------	
	Method GetFrame:Int()
		Return Self.frame
	End Method
	
	'|--------------------------------------------------------------------------------
	'| Stop animation event
	'|--------------------------------------------------------------------------------	
	Method StopAnimationEvent:Void()
		Self.frameSpeed = 0
	End Method
	
	'|--------------------------------------------------------------------------------
	'| Set animation event
	'|--------------------------------------------------------------------------------	
	Method SetAnimationEvent:Void(startFrame:Int=0, endFrame:Int=0, speed:Int=125, pingPong:Bool = False, loop:Bool = True)
		frame = startFrame
		frameStart = startFrame
		frameEnd = endFrame
		If startFrame > endFrame
			reverse = True
		Else
			reverse = False
		End
		Self.pingPong = pingPong
		Self.loop = loop
		frameSpeed = speed
		frameTimer = Millisecs()
		ping = 0
	End
	
	'|--------------------------------------------------------------------------------
	'| Update animation
	'|--------------------------------------------------------------------------------	
	Method UpdateAnimationEvent:Void()
		If frameSpeed > 0
			If Millisecs() > frameTimer + frameSpeed
				If Not reverse
					frame+=1
					If frame > frameEnd
						ResetAnim()
					End
				Else
					frame-=1
					If frame < frameEnd
						ResetAnim()
					End			
				End
				frameTimer = Millisecs()
			End	
		End
	End
	
	'|--------------------------------------------------------------------------------
	'| Reset animation
	'|--------------------------------------------------------------------------------	
	Method ResetAnim:Void()
		If loop Then
			If pingPong
				reverse = Not reverse
				frame = frameEnd
				Local ts% = frameStart
				frameStart = frameEnd
				frameEnd = ts
			Else
				frame = frameStart
			End
		Else
			If pingPong And ping <1
				reverse = Not reverse
				frame = frameEnd
				Local ts% = frameStart
				frameStart = frameEnd
				frameEnd = ts
				ping+=1
			Else
				frame = frameEnd
			End
		End
	End

	'|--------------------------------------------------------------------------------
	'| UPDATE
	'|--------------------------------------------------------------------------------
	Method Update:Void()	
		Self.UpdateAnimationEvent()
		Self.ManageRotationEvent()
		Self.ManageScaleEvent()
		Self.ManageAlphaEvent()
		Self.collision.UpdateByCenter(Self.position)
	End Method
	
	
	
	'|--------------------------------------------------------------------------------
	'| DRAW (add inside OnRender)
	'|--------------------------------------------------------------------------------
	Method Draw:Void()
		 
		  
		If Self.enable Then

			PushMatrix()
			Scale 1,1

			If Self.visible Then

				If Self.alpha>1.0 Then Self.alpha = 1.0
				If Self.alpha<0.0 Then Self.alpha = 0.0
					
				SetAlpha Self.alpha
				
				SetColor red, green, blue 

				DrawImage(	Self.bitmap.image,
							Self.position.x + Self.offset.x, 
							Self.position.y + Self.offset.y, 
							-Self.rotation, 
							Self.scale.x*Self.flip.x,
							Self.scale.y*Self.flip.y,
							Self.frame)	
			EndIf		
			PopMatrix
			SetBlend(0)
			SetAlpha 1 
		EndIf
	
	
	
	
		If DEBUG And Self.debug

					SetColor 255, 255, 0
					
					' collision shape
					SetAlpha 0.15
					SetColor 255,255,255
					DrawRect(
						Self.collision.Min.x, 
						Self.collision.Min.y, 
						Self.collision.size.x, Self.collision.size.y)
						
					SetAlpha 1
					' direction
					SetColor(0,255,0)
					DrawLine(	Self.position.x+Self.offset.x,
								Self.position.y+Self.offset.y,
								Self.position.x+Self.offset.x+Self.direction.x*32,
								Self.position.y+Self.offset.y+Self.direction.y*32)
					
					' center
					
					DrawCircle(	Self.position.x + Self.offset.x , 
								Self.position.y + Self.offset.y ,2)
					
					' inner circle
					SetAlpha 0.5
					SetColor(255,255,0)
					DrawCircle(	Self.position.x + Self.offset.x , Self.position.y + Self.offset.y ,Self.radius)
					SetColor(255,255,255)
					SetAlpha 1
					
					' collision radius
					SetColor(255,0,0)
					SetAlpha 0.5
					DrawCircle(	Self.position.x + Self.offset.x , Self.position.y + Self.offset.y ,Self.collision.radius)
					SetColor(255,255,255)
					SetAlpha 1
					
					' collision square
					
					SetAlpha 0.5
					SetColor(255,0,0)
					DrawRectOutline(Self.collision.Min.x + Self.offset.x , Self.collision.Min.y + Self.offset.y ,Self.collision.size.x,Self.collision.size.y)
					SetColor(255,255,255)
					SetAlpha 1
					
					'CONSOLE.fnt._DrawText("POS  :" + Self.position.ToString(),Self.position.x-Self.size.x/2,Self.position.y+Self.size.y/2.0)
					'CONSOLE.fnt._DrawText("DIR  :" + Self.direction.ToString(),Self.position.x-Self.size.x/2,Self.position.y+Self.size.y/2.0+10)
					'CONSOLE.fnt._DrawText("ANG  :" + FormatNumber(Self.rotation),Self.position.x-Self.size.x/2,Self.position.y+Self.size.y/2.0+20)
					'CONSOLE.fnt._DrawText("[" + Self.name+"]",Self.position.x-Self.size.x/2,Self.position.y+Self.size.y/2.0+30)
				EndIf
	End Method
	
	Method Free:Void()
		Self.bitmap.Free()
		Self.bitmap = Null
	End Method
End	